/**
 * 给定一个字符串仅包含YBR，表示命令。初始位于0位置且右边无边界限制。命令执行如下：
 *     Y指令表示在当前位置添加一个块；
 *     B指令表示先右移一格到达一个新位置，再在这个新位置添加一个块；
 *     R指令表示先将当前位置的块倍增一下，再添加一个块（假设当前位置本来有3块，则该指令过后变成7块）。
 * 还有Q个操作，一共分两类：
 *     p c: 将第p个位置的命令改为c；
 *     s e: 从零开始，依次执行[s,e]区间的命令，问最后的块数。
 * 对每个操作2，输出答案。
 * 设Di是第i个指令操作后当前位置的块数注意，不一定是第i ii个位置，因为一个命令不一定新增一个位置，不过这个并没有影响）。
 * 令Si是第i个操作后的总块数，令动态规划的列向量是
 *  [Di, Si, 1]
 *  YBR三个指令对应的系数矩阵分别是
 *    1 0 1    0 0 1    2 0 1
 *    0 1 1    0 1 1    1 1 1
 *    0 0 1    0 0 1    0 0 1
 *  维护系数矩阵的乘积即可，因此是一个单点修改区间查询的问题
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

using llt = long long;
using vi = vector<int>;
using pii = pair<int, int>;

llt const MOD = 1E9 + 7;

string S;

struct SegTree{ // 线段树带延迟

using llt = long long;

int N;

struct value_type {
    array<array<llt, 3>, 3> data;
	array<llt,  3> & operator [] (int p) {return data[p];} 
	const array<llt,  3> & operator [] (int p) const {return data[p];} 

	value_type() = default;

    bool isNull() const {return data[0][0] < 0;}    

	value_type(const array<array<llt, 3>, 3> & b):data(b){}

	void disp() const {
		for(const auto & a : data){
			for(auto i : a) cout << i << " ";
			cout << endl;
		}
	}

	value_type(char ch){
		if('Y' == ch){
			data = {
				array<llt, 3>{1, 0, 1},
				{0, 1, 1},
				{0, 0, 1}
			};
		}else if('B' == ch){
			data = {
				array<llt, 3>{0, 0, 1},
				{0, 1, 1},
				{0, 0, 1}
			};
		}else if('R' == ch){
            data = {
				array<llt, 3>{2, 0, 1},
				{1, 1, 1},
				{0, 0, 1}
			};
		}else{
			while(1);
		}

	}
};

vector<value_type> data; // 线段树

using lazy_type = value_type;
// vector<lazy_type> lazy; // 延迟标记

/// 从下往上计算信息，要变动
value_type _up_(const value_type & ls, const value_type & rs) {
    // assert(0);
	// if(ls.isNull()) return rs;
	// if(rs.isNull()) return ls;

	value_type ans;
    for(int i=0;i<3;++i)for(int j=0;j<3;++j){
		auto & d = ans[i][j]; d = 0;
		for(int k=0;k<3;++k){
			d = (d + ls[i][k] * rs[k][j] % MOD) % MOD;
		}
	}
	return ans;
}

/// 从上往下计算信息，要变动
void _dn_(int t, int s, int e, const lazy_type & delta) {
    // assert(0);
    data[t] = delta;
}

/// 初始化，清零，不用动
void init(int n) {
    data.assign((N = n) + 1 << 2, value_zero());
    // lazy.assign(n + 1 << 2, lazy_zero());
}

/// 这个函数不用动
void modify(int a, int b, const lazy_type & delta){
    _modify(1, 1, N, a, b, delta);
}

/// 这个函数不用动
value_type query(int a, int b){
    return _query(1, 1, N, a, b);
}

/// 这个函数不用动
void build(int n) {
    _build(1, 1, n);
}

/// 几乎不用动
value_type _query(int t, int s, int e, int a, int b) {
    if(a <= s and e <= b) {
        return data[t];
    }
    // _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    value_type ans = value_zero(); 
    if(a <= mid) ans = _up_(ans, _query(lson(t), s, mid, a, b));
    if(mid < b) ans = _up_(ans, _query(rson(t), mid + 1, e, a, b));
    return ans;
}

/// 几乎不用动
void _modify(int t, int s, int e, int a, int b, const lazy_type & delta) {
    if(a <= s and e <= b) {
        _dn_(t, s, e, delta);
        return;
    }
    // _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    if(a <= mid) _modify(lson(t), s, mid, a, b, delta);
    if(mid < b) _modify(rson(t), mid + 1, e, a, b, delta);
    _pushUp(t);
    return;
}

/// 这个函数不用动
void _pushUp(int t) {
    data[t] = _up_(data[lson(t)], data[rson(t)]);
}

/// 这个函数几乎不用动
void _pushDown(int t, int s, int e) {
    // if(lazy_zero() == lazy[t]) return;
    // auto & lz = lazy[t];
    // auto ls = lson(t), rs = rson(t);
    // int mid = (s + e) >> 1;

    // _dn_(ls, s, mid, lz);
    // _dn_(rs, mid + 1, e, lz);

    // lz = lazy_zero();
}


/// 几乎不用动
void _build(int t, int s, int e) {
    if(s == e) {
        // int x; cin >> x;
        data[t] = value_type(S[s]); // 注意提供value_type的初始化
        return; 
    }
    int mid = (s + e) >> 1;
    _build(lson(t), s, mid);
    _build(rson(t), mid + 1, e);
    _pushUp(t);
}

/// 辅助函数，视延迟的类型而变动
static const lazy_type & lazy_zero() {
    static const lazy_type LAZY0({array<llt, 3>{0}});
    return LAZY0; 
}

/// 辅助函数，视线段树信息类型而变动
static const value_type & value_zero() {
    static const value_type VALUE0({
		array<llt, 3>{1, 0, 0},
		{0, 1, 0},
		{0, 0, 1}
	});
    return VALUE0;
}

/// 这两个函数不用变动
static int lson(int x) {return x << 1;}
static int rson(int x) {return lson(x) | 1;}


};

int N, Q;
SegTree St;

void work(){
    cin >> N >> Q >> S;
	reverse(S.begin(), S.end());
	S = " " + S;
	St.init(N);
	St.build(N);
	// for(int i=1;i<=N;++i){
	// 	auto ans = St.query(1, i);
	// 	cout << "[" << 1 << ", " << i << "]: \n";
    //     ans.disp();
	// 	cout << "D = " << ans[0][2] << ", " << "S = " << ans[1][2] << endl;		
	// }
	char c;
	for(int op,a,b,q=1;q<=Q;++q){
        cin >> op >> a;
		if(1 == op){
            cin >> c;
			a = N - a + 1;
			S[a] = c;
			St.modify(a, a, SegTree::value_type(c)); 
		}else{
			cin >> b;
			a = N - a + 1;
			b = N - b + 1;
			if(a < b) swap(a, b);
            auto ans = St.query(b, a);
			// cout << "[" << a << ", " << b << "]: ";
			// cout << "D = " << ans[0][2] << ", " << "S = " << ans[1][2] << endl;
			auto tmp = ans[1][2];
			cout << tmp << "\n";
		}
	}
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int nofkase = 1;
    // cin >> nofkase;
    while(nofkase--) work();
    return 0;
}